package ru.stork.vasilisa.lang

import util.parsing.input.{StreamReader, CharArrayReader, Positional}
import io.Source
import ru.stork.vasilisa.exceptions.ValislisaParsingException
import java.io.{File, InputStream, InputStreamReader}

/**
 * Vasilisa Abstract Syntax Tree
 * @author Aleksey Fomkin <aleksey.fomkin@gmail.com>
 */
object Ast {

  /**
   * Return AST from string
   */
  @throws(classOf[ValislisaParsingException])
  def fromString(s: String) = VasilisaLanguageParser(new CharArrayReader(s.toCharArray))

  /**
   * Return AST from stream
   */
  @throws(classOf[ValislisaParsingException])
  def fromReader(s: InputStreamReader) = VasilisaLanguageParser(StreamReader(s))

  @throws(classOf[ValislisaParsingException])
  def fromStream(s: InputStream) = fromReader(new InputStreamReader(s))

  /**
   * Return AST from file path
   */
  @throws(classOf[ValislisaParsingException])
  def fromFile(path: String) = fromReader(Source.fromFile(path).reader)
}

/**
 *  Node of AST with position info.
 */
sealed trait Node extends Positional with NotNull {
  val source: Option[File] = None
}

/**
 * Dummy. Mostly used in tests
 */
case class EmptyNode() extends Node

/**
 * Nodes which includes this trait can be
 * defined in vasilisa trait level.
 */
sealed trait TypeLevelDeclaration extends Node

/**
 * Nodes which includes this trait can be defined in package level
 */
sealed trait PackageLevelDeclaration extends Node

/**
 * Nodes which includes this trait can be defined in version level.
 */
sealed trait VersionLevelDeclaration extends Node

/**
 * Represent package. Every package includes trait.
 * @example package com.company
 */
case class Package(name: List[String],
                   imports: List[Import],
                   trt: PackageLevelDeclaration)
                  (implicit override val source: Option[File])
  extends Node

case class Property(name: String,
                    typ: TypeDeclaration)
                   (implicit override val source: Option[File])
  extends TypeLevelDeclaration with VersionLevelDeclaration

case class Import(pkg: List[String],
                  name: String)
                 (implicit override val source: Option[File])
  extends PackageLevelDeclaration

case class Version(num: Int,
                   content: List[VersionLevelDeclaration])
                  (implicit override val source: Option[File])
  extends TypeLevelDeclaration

case class TypeDeclaration(name: String,
                           typeParameters: Option[List[TypeDeclaration]])
                          (implicit override val source: Option[File])
  extends Node

abstract class TypeNode extends PackageLevelDeclaration with TypeLevelDeclaration {
  val name: String
  val declarations: List[TypeLevelDeclaration]
}

// First vasilisa working model.
case class Variant(override val name: String,
                   params: Option[List[String]],
                   override val declarations: List[TypeLevelDeclaration])
                  (implicit override val source: Option[File])
  extends TypeNode

// Second vasilisa working model.
case class Model(override val name: String,
                 params: Option[List[String]],
                 override val declarations: List[TypeLevelDeclaration],
                 superType: Option[TypeDeclaration])
                (implicit override val source: Option[File])
  extends TypeNode
